#include "CG_parser.h"


typedef enum
{
	PARSE_LINE_SUCCESS,
	PARSE_LINE_SHORT,
	PARSE_LINE_COMMENT,
	PARSE_LINE_FAILED
}PARSE_LINE_RESULT;


PARSE_LINE_RESULT parse_location_line(char *line_str, char *name_str, float *x, float *y);
PARSE_LINE_RESULT parse_activity_line(char *buffer_activity, char *new_data);


PARSE_RESULT CG_parser::parse_location_file(CG_str_hash& ff_hash)
{
	char buffer_location[MAX_LINE_INPUT_LENGTH];
	float new_x;
	float new_y;
	char new_name[MAX_FF_NAME_LENGTH];
	PARSE_LINE_RESULT res;
	long line_number = 0;

	if(false == this->location_file.is_open())
	{
		std::clog << "parse_location_file: location file is not open" << endl;
		return PARSE_FAIL_LOCATION_FILE;
	}

	while(this->location_file.good() && false == this->location_file.eof())
	{
		line_number++;
		this->location_file.getline(buffer_location, MAX_LINE_INPUT_LENGTH);
		if(this->location_file.bad())
		{
			std::clog << "parse_location_file: read line error " << line_number << endl;
			return PARSE_FAIL_LOCATION_FILE;
		}

		new_x = -1;
		new_y = -1;
		memset(new_name, '\0', MAX_FF_NAME_LENGTH);
		res = parse_location_line(buffer_location, new_name, &new_x, &new_y);
		if(PARSE_LINE_FAILED == res)
		{
			std::clog << "parse_location_file: parse linr number " << line_number << endl;
			return PARSE_FAIL_LOCATION_FILE;
		}
		if(PARSE_LINE_SUCCESS == res)
		{
			CG_flip_flop *temp_ff;
			try
			{
				temp_ff = new CG_flip_flop(this->num_objects + 1, new_x, new_y, new_name);
			}
			catch(std::bad_alloc e)
			{
				cerr << "parse_location_file: Bad memory allocation" << endl;
				continue;
			}
			
			if(true == ff_hash.CG_ff_hash_insert(*temp_ff))
			{
				delete temp_ff;
				this->num_objects++;
			}
			else
			{
				delete temp_ff;
				std::clog << "parse_location_file: failed inser ff to grid " << line_number << endl;
				return PARSE_FAIL_LOCATION_FILE;
			}
		}
	}

	std::clog << "parse_location_file: parse success" << endl;
	std::clog << "hash map has " << ff_hash.CG_str_hash_get_size() << " Items" << endl;
	return PARSE_SUCCESS;
}


PARSE_RESULT CG_parser::parse_activity_files(CG_str_hash& ff_hash, CG_ff_grid& ff_grid)
{
	char buffer_activity[MAX_LINE_INPUT_LENGTH];
	char buffer_name[MAX_LINE_INPUT_LENGTH];
	char new_data[MAX_LINE_INPUT_LENGTH];
	PARSE_LINE_RESULT res;
	long line_number = 0;

	if(false == this->names_file.is_open())
	{
		std::clog << "parse_activity_files: names file is not open" << endl;
		return PARSE_FAIL_NAMES_FILE;
	}
	if(false == this->vectors_file.is_open())
	{
		std::clog << "parse_activity_files: vectors file is not open" << endl;
		return PARSE_FAIL_VECTORS_FILE;
	}

	while(this->names_file.good() && false == this->names_file.eof()
		&& this->vectors_file.good() && false == this->vectors_file.eof())
	{
		line_number++;
		memset(buffer_name, '\0', MAX_LINE_INPUT_LENGTH);
		this->names_file.getline(buffer_name, MAX_LINE_INPUT_LENGTH);
		if(this->names_file.bad())
		{
			std::clog << "parse_activity_files: names file - read line error " << line_number << endl;
			return PARSE_FAIL_NAMES_FILE;
		}
		
		memset(buffer_activity, '\0', MAX_LINE_INPUT_LENGTH);
		this->vectors_file.getline(buffer_activity, MAX_LINE_INPUT_LENGTH);
		if(this->vectors_file.bad())
		{
			std::clog << "parse_activity_files: vectors file - read line error " << line_number << endl;
			return PARSE_FAIL_VECTORS_FILE;
		}

		if(strlen(buffer_name) < MIN_LINE_INPUT_LENGTH)
		{
			continue;
		}
		if('/' == buffer_name[0] && '/' == buffer_name[1])
		{
			continue;
		}

		memset(new_data, '\0', MAX_LINE_INPUT_LENGTH);
		res = parse_activity_line(buffer_activity, new_data);
	
		if(PARSE_LINE_FAILED == res)
		{
			std::clog << "parse_activity_files: error parse vectors file - parse line number " << line_number << endl;
			return PARSE_FAIL_VECTORS_FILE;
		}

		if(PARSE_LINE_SUCCESS == res)
		{
			CG_flip_flop *curr_ff;

			try
			{
				curr_ff = new CG_flip_flop(ff_hash.CG_str_hash_get(buffer_name));
			}
			catch(std::bad_alloc e)
			{
				std::clog << "parse_activity_files: Bad memory allocation" << endl;
				continue;
			}
			
			if(FF_UNDEFINED == curr_ff->get_ID())
			{
				std::clog << "Cannot find ff with name " << buffer_name << " in hash DB." << endl;
				continue;
			}
			else
			{
				ff_hash.CG_str_hash_erase(buffer_name);
			}

			if(false == curr_ff->init_vector(new_data))
			{
				std::clog << "parse_activity_files: cannot init vector in ff " << buffer_name << endl;
				continue;
			}
			if(false == ff_grid.CG_ff_grid_insert(curr_ff))
			{
				std::clog << "parse_location_file: failed insert ff to grid " << line_number << endl;
			}
		}
	}

	std::clog << "parse_location_file: parse success" << endl;
	std::clog << "grid has " << ff_grid.CG_ff_grid_get_size() << " Items" << endl;
	return PARSE_SUCCESS;
}


CG_parser::CG_parser(char *lf_name, char *vf_name, char *nf_name)
{
	this->location_file.open(lf_name);
	if(this->location_file.fail() == true)
	{
		std::cerr << "Failed open locations file" << endl;
		return;
	}
	this->names_file.open(nf_name);
	if(this->names_file.fail() == true)
	{
		std::cerr << "Failed open names file" << endl;
		return;
	}
	this->vectors_file.open(vf_name);
	if(this->vectors_file.fail() == true)
	{
		std::cerr << "Failed open vectors file" << endl;
		return;
	}
	this->num_objects = 0;
}


CG_parser::~CG_parser(void)
{
	if(true == this->location_file.is_open())
	{
		this->location_file.close();
	}
	if(true == this->names_file.is_open())
	{
		this->names_file.close();
	}
	if(true == this->vectors_file.is_open())
	{
		this->vectors_file.close();
	}
}


PARSE_RESULT CG_parser::parse_data(CG_str_hash& ff_hash, CG_ff_grid& ff_grid)
{
	if(PARSE_SUCCESS != this->parse_location_file(ff_hash))
	{
		return PARSE_FAIL_LOCATION_FILE;
	}
	return this->parse_activity_files(ff_hash, ff_grid);
}


PARSE_LINE_RESULT parse_location_line(char *line_str, char *name_str, float *x, float *y)
{
	char *pch;
	char *start_coord;
	char *end_coord;
	char temp_coord[MAX_COORD_LENGTH];
	
	// check parameters
	if(NULL == line_str || NULL == name_str || NULL == x || NULL == y)
	{
		return PARSE_LINE_FAILED;
	}
	// check legal line length
	if(strlen(line_str) < MIN_LINE_INPUT_LENGTH)
	{
		return PARSE_LINE_SHORT;
	}
	// check for not a comment line
	if(line_str[0] == '/' && line_str[1] == '/')
	{
		return PARSE_LINE_COMMENT;
	}

	// parse the ff name
	pch = strchr(line_str, ' ');
	if(NULL == pch)
	{
		return PARSE_LINE_FAILED;
	}
	memset(name_str, '\0', MAX_FF_NAME_LENGTH);
	strncpy(name_str, line_str, pch - line_str);

	// parse the ff X coordinate
	start_coord = strchr(pch, '{');
	if(NULL == start_coord)
	{
		return PARSE_LINE_FAILED;
	}
	end_coord = strchr(start_coord, ' '); 
	if(NULL == end_coord)
	{
		return PARSE_LINE_FAILED;
	}
	strncpy(temp_coord, start_coord + 1, end_coord - (start_coord + 1));
	temp_coord[end_coord - (start_coord + 1)] = '\0';
	*x = (float)atof(temp_coord);

	// parse the ff Y coordinate
	while(*end_coord == ' ')
	{
		end_coord++;
	}
	start_coord = end_coord;
	end_coord = strchr(start_coord, ' ');
	if(NULL == end_coord)
	{
		return PARSE_LINE_FAILED;
	}
	strncpy(temp_coord, start_coord, end_coord - start_coord);
	temp_coord[end_coord - start_coord] = '\0';
	*y = (float)atof(temp_coord);

	return PARSE_LINE_SUCCESS;
}


PARSE_LINE_RESULT parse_activity_line(char *buffer_activity, char *new_data)
{
	char *pch;
	
	// check parameters
	if(NULL == buffer_activity || NULL == new_data)
	{
		return PARSE_LINE_FAILED;
	}
	// check legal line length
	if(strlen(buffer_activity) < MIN_LINE_INPUT_LENGTH)
	{
		return PARSE_LINE_SHORT;
	}
	// check for not a comment line
	if(buffer_activity[0] == '/' && buffer_activity[1] == '/')
	{
		return PARSE_LINE_COMMENT;
	}

	// parse the ff name
	pch = strchr(buffer_activity, ' ');
	if(NULL == pch)
	{
		return PARSE_LINE_FAILED;
	}
	strcpy(new_data, pch + 1);
	new_data[strlen(buffer_activity) - (pch - buffer_activity)] = '\0';

	return PARSE_LINE_SUCCESS;
}